 type Callback<T = any> = (err: Error | null, result?: T) => void;
type Thunk<T> = (callback: Callback<T>) => void;
type ThunkifiedFn<T> = (...args: any[]) => Thunk<T>;

/**
 * 将回调风格的函数转换为 Thunk 函数（单参数回调形式）
 * @param fn 原函数，需满足回调在最后一位（如 `(arg1, arg2, callback) => void`）
 * @returns 返回一个 Thunk 函数（`(...args) => (callback) => void`）
 * @example
 * 示例：转换 fs.readFile
 * import fs from 'fs';
 * const readFileThunk = thunkify<string>(fs.readFile);
 * readFileThunk('./file.txt')((err, data) => {
 *    if (err) console.error(err);
 *    else console.log(data); // string 类型
 * });
 */
export function thunkify<T>(fn: (...args: any[]) => void): ThunkifiedFn<T> {
  return function (this: any, ...args: any[]) {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const ctx = this
    return function (callback: Callback<T>) {
      let called = false // 防止多次回调
      const wrappedCallback = (...results: any[]) => {
        if (called) return
        called = true
        // 处理 Node.js 风格回调 (err, result)
        if (results[0] instanceof Error) {
          callback(results[0])
        } else {
          callback(null, ...results)
        }
      }

      try {
        // 拼接参数并执行原函数
        fn.apply(ctx, [...args, wrappedCallback])
      } catch (err) {
        // 同步错误直接回调
        if (!called) {
          called = true
          callback(err instanceof Error ? err : new Error(String(err)))
        }
      }
    }
  }
}
